﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Models;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Data.SqlClient;
using System.Windows.Media.Imaging;
using System.Windows;
using System.Runtime.InteropServices;

namespace XmlDataHandler
{
    public class ImageHandler
    {

        #region Fields

        AdminPanelDataAccess dataAccess;

        #endregion

        #region Creation

        public ImageHandler(AdminPanelDataAccess dataAccess)
        {
            this.dataAccess = dataAccess;
        }

        #endregion

        #region Public Methods

        public void UploadFile(string path, int genericItemId, int itemId)
        {
            // laver filestream på stien til billedet
            var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);

            // instantiate byte array med korrekt længde
            byte[] img = new Byte[fileStream.Length];

            // læs fra filestream til byte array
            fileStream.Read(img, 0, Convert.ToInt32(img.Length));

            // instantiate image object fra byte array
            Image image = ByteArrayToImage(img);
           
            // definer bredde og højde billedet skal resizes til
            var resizedSize = new System.Drawing.Size(153, 200);
            var originalSize = new System.Drawing.Size(411, 538);

            //ny orginal 411, 538

            // instantiate resized image
            Image resizedImage = ResizeImage(image, resizedSize);
            Image originalImage = ResizeImage(image, originalSize);

            byte[] original = ImageToByteArray(originalImage);
            byte[] resized = ImageToByteArray(resizedImage);

            try
            {    
                dataAccess.OpenConnection();
                int colorId = dataAccess.GetColorIdByItem(itemId);
                
                // hvis der findes et billede med nuværende GenericItemId og ColorId, return
                if (dataAccess.ImageExists(genericItemId, colorId) > 0)
                {
                    throw new Exception("Der findes allerede et billede til den vare.");    
                }

                dataAccess.BeginTransaction();

                int imageId = dataAccess.InsertImage(original, resized);
                dataAccess.InsertItemPicture(genericItemId, colorId, imageId);

                dataAccess.CommitTransaction();
            }
            catch (SqlException sqle)
            {
                dataAccess.RollBackTransaction();
                Console.WriteLine(sqle.Message);
                throw new Exception("There was an error inserting into the database.");
            }

        }
        
        // henter billede fra databasen, og konverterer til et bitmap image
        public ImageModel GetItemImage(int genericItemId, int itemId)
        {

            int colorId = dataAccess.GetColorIdByItem(itemId);

            ImageData imageData = dataAccess.GetImage(genericItemId, colorId);

            // hvis der var fejl ved oprettelse af ImageData object, return
            if (imageData == null) 
                return null;

            
            Image img = ByteArrayToImage(imageData.Original);

            // konverter Image objekt til Bitmap, og tildel StreamSource et nyt MemoryStream
            BitmapImage sourcedImg = GetSourceFromImage(img);

            var imageModel = new ImageModel(genericItemId, colorId, sourcedImg);
            return imageModel;
        }

        #endregion

        #region Private Methods

        public static Image GetImageFromStream(string path)
        {
            // laver filestream på stien til billedet
            var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);

            // instantiate byte array med korrekt længde
            byte[] img = new Byte[fileStream.Length];

            // læs fra filestream til byte array
            fileStream.Read(img, 0, Convert.ToInt32(img.Length));

            // instantiate image object fra byte array
            return StaticByteArrayToImage(img);           
        }

        // returner et billedes source
        private BitmapImage GetSourceFromImage(Image image)
        {
            MemoryStream ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);
            ms.Position = 0;
            BitmapImage bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.StreamSource = ms;
            bitmap.EndInit();

            return bitmap;
        }

        // laver en resized version af billedet.
        private Image ResizeImage(Image imgToResize, System.Drawing.Size size)
        {
            Bitmap newImage = new Bitmap(size.Width, size.Height);
            using (Graphics gr = Graphics.FromImage(newImage))
            {
                gr.SmoothingMode = SmoothingMode.HighQuality;
                gr.InterpolationMode = InterpolationMode.HighQualityBicubic;
                gr.PixelOffsetMode = PixelOffsetMode.HighQuality;
                gr.DrawImage(imgToResize, new Rectangle(0, 0, size.Width, size.Height));
            }
            return newImage;
        }

        // convert byte array til image
        private Image ByteArrayToImage(byte[] byteArray)
        {
            var ms = new MemoryStream(byteArray);
            return Image.FromStream(ms);
        }

        // samme som ovenstående, men statisk
        public static Image StaticByteArrayToImage(byte[] byteArray)
        {
            var ms = new MemoryStream(byteArray);
            return Image.FromStream(ms);
        }

        // convert Image to byte array
        private byte[] ImageToByteArray(Image image)
        {
            var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Jpeg);

            return ms.ToArray();
        }

        // convert bitmap image til bitmap
        public static Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
        {
            using (var outStream = new MemoryStream())
            {
                BitmapEncoder enc = new BmpBitmapEncoder();
                enc.Frames.Add(BitmapFrame.Create(bitmapImage));
                enc.Save(outStream);
                System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);

                // return bitmap; <-- leads to problems, stream is closed/closing ...
                return new Bitmap(bitmap);
            }
        }

        // convert bitmap til bitmap image
        public static BitmapImage Bitmap2BitmapImage(Bitmap bitmap)
        {
            using (var ms = new MemoryStream())
            {
                bitmap.Save(ms, ImageFormat.Png);
                ms.Position = 0;
                BitmapImage bi = new BitmapImage();
                bi.BeginInit();
                bi.StreamSource = ms;
                bi.EndInit();

                return bi;
            }
        }

        [DllImport("gdi32")]
        static extern int DeleteObject(IntPtr o);

        // returner bitmap source fra et bitmap object
        public static BitmapSource LoadBitmap(Bitmap source)
        {
            IntPtr ip = source.GetHbitmap();
            BitmapSource bs = null;
            try
            {
                bs = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ip,
                   IntPtr.Zero, Int32Rect.Empty,
                   System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(ip);
            }

            return bs;
        }

        #endregion
        
    }
}
